#include "StdAfx.h"
#include "ControlContext.h"
#include "TargetController.h"
#include "TargetControlLogic.h"
#include "Target.h"

#include "EntityControl.h"
#include "PhysicsEntity.h"

#include "Launcher.h"

TargetController::TargetController(
	TargetControlLogic* targetControlLogic)
	:targetControlLogic(targetControlLogic)
{
	currentTargetIndex = 0;
	currentProjectileTargetIndex = 0;
}

TargetController::~TargetController(void)
{
	delete targetControlLogic;
}

void TargetController::apply(
	EntityControl* entityControl, const ControlContext& context)
{
	NxActor* actor = entityControl->getPhysicsActor()->getNxActor();
	Ogre::SceneNode* ogreNode = entityControl->getPhysicsActor()->getOgreNode();

	/*PhysicsEntity* bulletActor = entityControl->getPhysicsActor();
	Ogre::SceneNode* parentNode = bulletActor->getParentSceneNode();*/

	// If target exists
	if( !targetControlLogic->targets.empty() )
	{

		/*bulletActor->disableDeactivation();
		bulletActor->setLinearVelocity(0.0,0.0,0.0);
		bulletActor->getBulletRigidBody()->setAngularVelocity(btVector3(0.0,0.0,0.0));*/
		actor->setLinearVelocity(NxVec3(0,0,0));
		actor->setAngularVelocity(NxVec3(0,0,0));

		
		// Get the next target
		Target* target = targetControlLogic->
			targets.at(currentTargetIndex);

		// Distance from target
		Ogre::Vector3 distanceFromTarget =
			target->position - ogreNode->getPosition();

		//Ogre::Vector3 mDestination = target->position;
		//Ogre::Vector3 mDirection = mDestination-ogreNode->getPosition();
		//Ogre::Real mDistance = mDirection.normalise();

		//Ogre::Vector3 src = ogreNode->getOrientation() * Ogre::Vector3::UNIT_X;
		///*if(target->mark != NULL) 
		//{
		//	Ogre::Quaternion quat = src.getRotationTo(target->mark->getParentSceneNode()->getPosition());
		//	ogreNode->rotate(quat);
		//}*/

		//if(mDistance < target->proximityRadius)
		//{
		//	currentTargetIndex++;
		//	if(currentTargetIndex >= targetControlLogic->targets.size())
		//		currentTargetIndex = 0;
		//	
		//	mDirection = targetControlLogic->targets.at(currentTargetIndex)->position - ogreNode->getPosition();
		//	if ((1.0f + src.dotProduct(mDirection)) < 0.0001f) 
		//	{
		//		ogreNode->yaw(Ogre::Degree(180));
		//	}
		//	else
		//	{
		//		
		//		Ogre::Quaternion quat = src.getRotationTo(mDirection);						
		//		ogreNode->rotate(quat);
		//	} 
		//		
		//}

		//ogreNode->translate(mDirection*context.dt*10, Ogre::Node::TS_LOCAL);



		// Add distance from mark
		if(target->mark != NULL)
			distanceFromTarget += target->mark->getParentSceneNode()->getPosition();

		//if( !target->mark.expired() )
		//	distanceFromTarget += target->mark.lock()->
		//		getParentSceneNode()->getPosition();

		// If target reached, advance to thy next target
		if(distanceFromTarget.length() < target->proximityRadius)
		{
			currentTargetIndex++;
			if(currentTargetIndex >= targetControlLogic->targets.size())
				currentTargetIndex = 0;
		}

		// Direction to the mark
		Ogre::Vector3 targetDirection =
			distanceFromTarget.normalisedCopy();

		// Get the current facing direction
		Ogre::Vector3 ahead =
			ogreNode->getOrientation() * Ogre::Vector3::UNIT_Z;

		// Get the turning axis
		Ogre::Vector3 turnAxis =
			ahead.crossProduct(targetDirection);
		actor->raiseBodyFlag(NX_BF_DISABLE_GRAVITY);
		//Ogre::Vector3 force = ahead * ahead.dotProduct(targetDirection) * targetControlLogic->maxForce;
		Ogre::Vector3 torque = turnAxis * targetControlLogic->maxTorque;
		Ogre::Vector3 force = targetDirection * targetControlLogic->maxForce;
		actor->addForce(NxVec3(force.x, force.y, force.z)*40);
		//actor->addForce(NxVec3(targetDirection.x, targetDirection.y, targetDirection.z)*1000);
		actor->addTorque(NxVec3(torque.x, torque.y, torque.z)*450000000);

	}
		ogreNode->setOrientation(actor->getGlobalOrientationQuat().w,
				actor->getGlobalOrientationQuat().x,
				actor->getGlobalOrientationQuat().y,
				actor->getGlobalOrientationQuat().z);
		ogreNode->setPosition(actor->getGlobalPosition().x,
				actor->getGlobalPosition().y,
				actor->getGlobalPosition().z);

	// Shooting from launchers
	if( !targetControlLogic->launchers.empty() )
	{
		// Iterate for every attached launcher
		std::vector<Launcher*>::iterator iLauncher = targetControlLogic->launchers.begin();
		while(iLauncher != targetControlLogic->launchers.end())
		{
			Launcher* launcher = *iLauncher;

			// Update cooldown, if 0, then shoot
			if( launcher->setCooldownRemaining(launcher->getCooldownRemaining() - context.dt) <= 0 )
			{

				// Create new Projectile from current launcher
				TargetController::Projectile newProjectile;
				newProjectile.modelMeshName = launcher->getModelMeshName();
				newProjectile.position = launcher->getPosition();


				// Get the point of the entity looking at
				Ogre::Vector3 entityLookingAtPoint = Ogre::Vector3::ZERO;
				Target* target;
				if( !targetControlLogic->ProjectileTargets.empty() )
				{
					// Get the next target
					target = targetControlLogic->
						ProjectileTargets.at(currentProjectileTargetIndex);

					currentProjectileTargetIndex++;
					if(currentProjectileTargetIndex >= targetControlLogic->ProjectileTargets.size())
						currentProjectileTargetIndex = 0;

					if(target->mark != NULL)
						entityLookingAtPoint = target->mark->getParentSceneNode()->getPosition();
					else
						entityLookingAtPoint = target->position;
				}
				entityLookingAtPoint -= launcher->getPosition();

				Ogre::Vector3 entityDirection = entityLookingAtPoint - entityControl->getModelActor()->getParentSceneNode()->getPosition();

				entityDirection.normalise();

				// Get the direction
				Ogre::Vector3 launcherVelocity = launcher->getVelocity();
				newProjectile.velocity = Ogre::Vector3(
					entityDirection.x * launcherVelocity.x,
					entityDirection.y * launcherVelocity.y,
					entityDirection.z * launcherVelocity.z);

				// Add the new Projectile to the list
				projectiles.push_back(newProjectile);

				// Reset cooldown
				launcher->resetCooldown();
			}

			iLauncher++;
		}
	}

}

bool TargetController::isSpawningNeeded()
{
	return !projectiles.empty();
}

TargetController::Projectile TargetController::getNextSpawnItem()
{
	TargetController::Projectile projectile = projectiles.back();
	projectiles.pop_back();
	return projectile;
}
